package com.sea.base.fragment.opt

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultRegistry
import androidx.activity.result.ActivityResultRegistryOwner
import androidx.activity.result.contract.ActivityResultContract
import androidx.annotation.CallSuper
import androidx.annotation.MainThread
import androidx.core.app.ActivityOptionsCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.ViewModelStore
import com.sea.base.ext.global.log
import com.sea.base.ext.obs.addObserver
import com.sea.base.ext.view.doOnDestroyed
import com.sea.base.ext.view.requireActivity
import com.sea.base.fragment.BaseKtFragment
import com.sea.base.ui.IUIContext
import java.util.concurrent.atomic.AtomicReference

/**
 * 这个FragmentItem基于view的生命周期，解决ViewPager等控件会导致Fragment的生命周期和view不一致的问题
 * 也就是说view没了就是Destroy，不可见就是Pause，和Activity基本保持一致的效果
 */
abstract class FragmentItem : IUIContext {
    companion object {
        internal const val KEY_FRAGMENT_CLASS_NAME = "FragmentItemParent\$FragmentClassName"

        /**
         * 为当前类创建一个真正的Fragment
         */
        @JvmStatic
        fun <T : FragmentItem> createFragment(clazz: Class<T>, args: Bundle? = null): BaseKtFragment<*> =
            FragmentItemParent().apply {
                @Suppress("DEPRECATION")
                arguments = createArguments(clazz, args)
            }

        inline fun <reified T : FragmentItem> createFragment(args: Bundle? = null) = createFragment(T::class.java, args)
        inline fun <reified T : FragmentItem> createFragment(addBundle: Bundle.() -> Unit) = createFragment(T::class.java, Bundle().apply { addBundle() })

        @JvmStatic
        fun <T : FragmentItem> createArguments(clazz: Class<T>, args: Bundle? = null) = (args ?: Bundle()).also {
            it.putString(KEY_FRAGMENT_CLASS_NAME, clazz.name)
        }

        inline fun <reified T : FragmentItem> createArguments(args: Bundle? = null) = createArguments(T::class.java, args)
    }

    private var _frag: FragmentItemParent? = null
    private val frag get() = _frag ?: throw IllegalStateException("请不要在attach前调用")

    private val mLifecycleRegistry = LifecycleRegistry(this)
    private val mOnPreAttachedListeners = ArrayList<() -> Unit>()
    private val vmStore = ViewModelStore()

    var arguments: Bundle? = null
        internal set
    val attachFragment: Fragment get() = frag

    internal fun attach(frag: FragmentItemParent, savedInstanceState: Bundle?) {
        _frag = frag
        mOnPreAttachedListeners.forEach { it.invoke() }
        val fragObs = frag.lifecycle.addObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_CREATE -> {
                    platformCreate(savedInstanceState)
                }

                Lifecycle.Event.ON_START -> {
                    platformStart()
                }

                Lifecycle.Event.ON_RESUME -> {
                    platformResume()
                }

                Lifecycle.Event.ON_PAUSE -> {
                    platformPause()
                }

                Lifecycle.Event.ON_STOP -> {
                    platformStop()
                }

                Lifecycle.Event.ON_DESTROY -> {
                    platformDestroy()
                }

                Lifecycle.Event.ON_ANY -> {
                    "未知".log("FragmentItem")
                }
            }
        }
        this.doOnDestroyed {
            frag.lifecycle.removeObserver(fragObs)
        }
    }

    internal fun platformStart() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
        onStart()
    }

    @CallSuper
    protected open fun onStart() {
    }

    internal fun platformCreate(savedInstanceState: Bundle?) {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
        onCreate(savedInstanceState)
    }

    @CallSuper
    protected open fun onCreate(savedInstanceState: Bundle?) {
    }

    internal fun platformCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return onCreateView(inflater, container, savedInstanceState)
    }

    protected abstract fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?

    internal fun platformResume() {
        if (frag.isVisibleActivity) {
            mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
            onResume()
        }
    }

    @CallSuper
    protected open fun onResume() {
    }

    internal fun platformPause() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
        onPause()
    }

    @CallSuper
    protected open fun onPause() {
    }

    internal fun platformStop() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
        onStop()
    }

    @CallSuper
    protected open fun onStop() {
    }

    internal fun platformDestroy() {
        mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
        onDestroy()
    }

    @CallSuper
    protected open fun onDestroy() {
    }

    @CallSuper
    @Deprecated("建议使用registerForActivityResult")
    open fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    }

    /**
     * 这里你可以临时将数据保存到Fragment上
     */
    protected fun saveDataToFragment(key: Int, value: Any) {
        frag.itemSaveData!![key] = value
    }

    protected fun <T> getSavedFragmentData(key: Int): T? = frag.itemSaveData!![key] as? T

    override fun getLifecycle(): Lifecycle = mLifecycleRegistry

    /**
     * 该vm不支持Destroy后复原
     */
    override fun getViewModelStore() = vmStore

    @MainThread
    override fun <I, O> registerForActivityResult(
        contract: ActivityResultContract<I, O>,
        callback: ActivityResultCallback<O>
    ): ActivityResultLauncher<I> {
        return prepareCallInternal(contract, {
            val host = frag.host
            if (host is ActivityResultRegistryOwner) host.activityResultRegistry else requireActivity.activityResultRegistry
        }, callback)
    }

    @MainThread
    override fun <I, O> registerForActivityResult(
        contract: ActivityResultContract<I, O>,
        registry: ActivityResultRegistry,
        callback: ActivityResultCallback<O>
    ): ActivityResultLauncher<I> {
        return prepareCallInternal(contract, { registry }, callback)
    }

    private fun <I, O> prepareCallInternal(
        contract: ActivityResultContract<I, O>,
        registryProvider: () -> ActivityResultRegistry,
        callback: ActivityResultCallback<O>
    ): ActivityResultLauncher<I> {
        // Throw if attempting to register after the Fragment is CREATED.
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
            throw IllegalStateException(
                "Fragment " + this + " is attempting to "
                        + "registerForActivityResult after being created. Fragments must call "
                        + "registerForActivityResult() before they are created (i.e. initialization, "
                        + "onAttach(), or onCreate())."
            )
        }
        val ref = AtomicReference<ActivityResultLauncher<I>>()
        // We can't call generateActivityResultKey during initialization of the Fragment
        // since we need to wait for the mWho to be restored from saved instance state
        // so we'll wait until we have all the information needed to register  to actually
        // generate the key and register.
        registerOnPreAttachListener {
            val key = frag.generateActivityResultKey2()
            val registry = registryProvider.invoke()
            ref.set(registry.register(key, this@FragmentItem, contract, callback))
        }
        return object : ActivityResultLauncher<I>() {
            override fun launch(input: I, options: ActivityOptionsCompat?) {
                val delegate = ref.get() ?: throw java.lang.IllegalStateException(
                    "Operation cannot be started before fragment "
                            + "is in created state"
                )
                delegate.launch(input, options)
            }

            override fun unregister() {
                val delegate = ref.getAndSet(null)
                delegate?.unregister()
            }

            override fun getContract(): ActivityResultContract<I, *> {
                return contract
            }
        }
    }

    private fun registerOnPreAttachListener(callback: () -> Unit) {
        //If we are already attached, we can register immediately
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)) {
            callback.invoke()
        } else {
            // else we need to wait until we are attached
            mOnPreAttachedListeners.add(callback)
        }
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////
    // IUIContext的实现
    /////////////////////////////////////////////////////////////////////////////////////////////////

    override val isFinished get() = lifecycle.currentState == Lifecycle.State.DESTROYED
    override val currentFragmentManager get() = frag.childFragmentManager
    override val rootView get() = frag.view
    override val realDelegate get() = this

    override fun requireViewLifecycle() = lifecycle

    override fun viewLifecycleWithCallback(run: (Lifecycle?) -> Unit) {
        run.invoke(lifecycle)
    }

    override fun startActivity(intent: Intent, options: Bundle?) {
        frag.startActivity(intent, options)
    }

    override fun startActivityForResult(intent: Intent, requestCode: Int, options: Bundle?) {
        frag.startActivityForResult(intent, requestCode, options)
    }

    override fun getActivity() = frag.activity

    override fun getContext() = frag.context

    override fun getLayoutInflater() = frag.layoutInflater
}